#include "xregister_client.h"
#include <protobuf/xmsg_com.pb.h>
#include <thread_pool/XThreadPool.h>
#include <XTools.h>
#include <thread>
#include <sstream>
#include <fstream>
using namespace std;
using namespace xmsg;

static XServiceMap *static_service_map = nullptr;
static XServiceMap *static_client_map = nullptr;
static std::mutex static_server_map_mutex;

void XRegisterClient::RegisterServer(const char *server_name, unsigned short server_port, const char *server_ip)
{
    // 发送消息到服务器
    // 服务器连接是否成功
    if (server_name)
    {
        memset(server_name_, 0, sizeof(server_name_));
        strcpy(server_name_, server_name);
    }
    if (server_ip)
    {
        memset(server_ip_, 0, sizeof(server_ip_));
        strcpy(server_ip_, server_ip);
    }
    server_port_ = server_port;
    // 设置自动连接
    setAutoConnect(true);
    // 开始连接
    StartConnect();
}

void XRegisterClient::GetServiceReq(const char *server_name)
{
    XCOM_LOG_DEBUG("GetServiceReq");
    XGetServiceReq req;
    if (server_name)
    {
        req.set_name(server_name);
        req.set_type(XServiceType::ONE);
    }
    else
    {
        req.set_type(XServiceType::ALL);
        // req.set_name("all");
    }
    SendMsg(MsgType::MSG_GET_SERVICE_REQ, &req);
}

void XRegisterClient::RegisterRes(XMsgHead *head, XMsg *msg)
{
    XCOM_LOG_DEBUG("RegisterRes");
    XMessageRes res;
    if (!res.ParseFromArray(msg->data, msg->recv_size))
    {
        XCOM_LOG_ERROR("RegisterRes:ParseFromArray error");
        return;
    }
    if (res.return_() != XMessageRes::SUCCESS)
    {
        XCOM_LOG_ERROR("注册失败：" << res.msg());
        return;
    }
    XCOM_LOG_DEBUG("注册成功");
}

void XRegisterClient::GetServiceRes(XMsgHead *head, XMsg *msg)
{
    auto lock = std::unique_lock<std::mutex>(static_server_map_mutex);
    bool is_all = false;
    XServiceMap *cache_map = nullptr;
    XServiceMap tmp;
    cache_map = &tmp;
    if (!static_service_map)
    {
        static_service_map = new XServiceMap();
        cache_map = static_service_map;
        is_all = true;
    }
    if (!cache_map->ParseFromArray(msg->data, msg->recv_size))
    {
        XCOM_LOG_ERROR("GetServiceRes:ParseFromArray error");
        return;
    }
    if (cache_map->type() == XServiceType::ALL)
    {
        is_all = true;
    }
    // 内存缓存刷新
    if (cache_map == static_service_map)
    {
        // 内存已经刷新
    }
    else
    {
        XCOM_LOG_DEBUG("刷新内存缓存");
        if (is_all)
        {
            static_service_map->CopyFrom(*cache_map);
        }
        else
        {   // 将刚读到的数据存入sevice_map
            auto cmap=cache_map->mutable_service_map();
            // 取第一个服务
            if (!cmap || cmap->empty())
                return;
            auto once = cmap->begin();

            auto smap = static_service_map->mutable_service_map();
            // 修改缓存
            (*smap)[once->first] = once->second;
        }
    }
    // 磁盘缓存刷新 后期要考虑刷新频率，太高会损坏磁盘
    stringstream name;
    name << "register_" << server_name_ << "_" << server_ip_ << "_" << server_port_ << ".txt";
    string s = name.str();
    if (!static_service_map)
    {
        return;
    }
    ofstream out = ofstream(s, ios::out | ios::binary);
    if (!out.is_open())
    {
        return;
    }
    static_service_map->SerializeToOstream(&out);
    out.close();
}
/**
 * 获取所有服务的映射
 *
 * 本函数用于获取当前所有已注册服务的映射信息它通过锁定互斥量来保证线程安全，
 * 并确保在多线程环境下安全地懒加载静态客户端映射
 *
 * @return 返回指向XServiceMap对象的指针，该对象包含所有服务的映射信息如果服务映射为空，则返回nullptr
 */
XServiceMap *XRegisterClient::GetAllService()
{
    auto lock = std::unique_lock<std::mutex>(static_server_map_mutex);
    loadLocalFile();
    if (!static_service_map)
        return nullptr;
    if (!static_client_map)
    {
        static_client_map = new XServiceMap();
    }
    static_client_map->CopyFrom(*static_service_map);
    return static_client_map;
}

/**
 * @brief 复制所有服务信息到一个新的XServiceMap对象中
 *
 * 该函数主要用于当需要获取当前所有服务的信息时调用它会返回一个包含所有服务信息的XServiceMap对象
 * 在多线程环境下，该函数通过加锁来保证数据的一致性和完整性
 *
 * @return XServiceMap 包含所有服务信息的XServiceMap对象如果static_server_map为空，则返回一个空的XServiceMap对象
 */
XServiceMap XRegisterClient::CopyAllService()
{
    // 加锁，保证static_server_map的线程安全
    auto lock = std::unique_lock<std::mutex>(static_server_map_mutex);

    // 检查static_server_map是否为空如果为空，直接返回一个空的XServiceMap对象
    if (!static_service_map)
        return XServiceMap();

    // 创建一个XServiceMap对象用于存储所有服务的信息
    XServiceMap ret;

    // 从static_server_map中复制所有服务信息到ret对象中
    ret.CopyFrom(*static_service_map);

    // 返回包含所有服务信息的XServiceMap对象
    return ret;
}

XServiceMap::XServiceList XRegisterClient::GetService(const char *service_name, int timeout_sec)
{
    // 等待连接
    int count = timeout_sec * 1000 / 10; // 10ms一次
    int i = 0;
    for (; i < count; ++i)
    {
        if (isConnected())
        {
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    if (!isConnected())
    {
        XCOM_LOG_ERROR("连接等待超时!");
        auto lock = std::unique_lock<std::mutex>(static_server_map_mutex);
        if (!static_service_map)
        {
            // 磁盘缓存刷新 后期要考虑刷新频率，太高会损坏磁盘
            loadLocalFile();
        }
        return XServiceMap::XServiceList();
    }
    // 发送获取微服务请求
    GetServiceReq(service_name);
    // 等待响应
    for (; i < count;)
    {
        auto lock = std::unique_lock<std::mutex>(static_server_map_mutex);
        if (!static_service_map)
        {
            lock.unlock();
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            ++i;
            continue;
        }
        auto m = static_service_map->mutable_service_map();
        if (!m)
        {
            lock.unlock();
            // 发送获取微服务请求
            GetServiceReq(service_name);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            i += 10;
            continue;
        }
        auto s = m->find(service_name);
        if (s == m->end())
        {
            lock.unlock();
            // 发送获取微服务请求
            GetServiceReq(service_name);
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            i += 10;
            continue;
        }
        return static_service_map->service_map().find(service_name)->second;
    }
    return XServiceMap::XServiceList();
}

void XRegisterClient::Wait()
{
    XThreadPool::Wait();
}

void XRegisterClient::connectedCB()
{
    XCOM_LOG_DEBUG("connected start send MSG_REGISTER_REQ");
    // 创建一个注册请求对象
    XRegisterReq req;
    // 设置注册请求中的服务器名称
    req.set_name(std::string(server_name_));
    // 设置注册请求中的服务器端口
    req.set_port(server_port_);
    // 设置注册请求中的服务器IP地址
    req.set_ip(std::string(server_ip_));
    // 发送注册请求消息
    SendMsg(MSG_REGISTER_REQ, &req);
}

bool XRegisterClient::loadLocalFile()
{
    if(!static_service_map){
        static_service_map = new XServiceMap();
    }
    // 磁盘缓存刷新 后期要考虑刷新频率，太高会损坏磁盘
    stringstream name;
    name << "register_" << server_name_ << "_" << server_ip_ << "_" << server_port_ << ".txt";
    string s = name.str();
    ifstream in = ifstream(s, ios::in | ios::binary);
    if (!in.is_open())
    {
        XCOM_LOG_DEBUG("loadLocalFile fail");
        return false;
    }
    static_service_map->ParseFromIstream(&in);
    in.close();
    return true;
}
